<script setup lang="ts">
    import * as d3 from 'd3';
    import { reactive,onMounted,useTemplateRef } from 'vue';

    const chartBox = useTemplateRef('chart');

    const nodes = reactive([
        { id: 1, name: '刘备', type: '皇上' },
        { id: 2, name: '关羽', type: '将军' },
        { id: 3, name: '张飞', type: '将军' },
        { id: 4, name: '诸葛亮', type: '丞相' },
        { id: 5, name: '小兵1', type: '士兵' },
        { id: 6, name: '小兵2', type: '士兵' },
      ])

    const links = reactive([
        { source: 1, target: 2, relate: '将军' },
        { source: 1, target: 3, relate: '将军' },
        { source: 1, target: 4, relate: '丞相' },
        { source: 2, target: 5, relate: '下属' },
        { source: 2, target: 6, relate: '下属' },
        { source: 3, target: 5, relate: '下属' },
      ])


    onMounted(()=>{
        drawChart();
    })

    const drawChart = () => {
      console.log('draw chart.................');
      const data = {
        nodes: nodes,
        links: links,
      };
      const width = 600;
      const height = 400;
      const svg = d3.select(chartBox.value)
        .append('svg')
        .attr('width', width)
        .attr('height', height);
      const g = svg.append('g');
      
      const simulation = d3.forceSimulation(data.nodes)
        .force('link', d3.forceLink(data.links).id(d => d.id).distance(150))
        .force('charge', d3.forceManyBody())
        .force('center', d3.forceCenter(width/2, height / 2));

      const link = g.selectAll('line')
        .data(data.links)
        .enter()
        .append('line')
        .attr('stroke', '#999')
        .attr('stroke-width', 2);

      const node = g.selectAll('.node')
        .data(data.nodes)
        .enter()
        .append('g')
        .attr('class', 'node')
        .style('fill', 'black');

      node.append('circle')
        .attr('r', 18)
        .attr('fill', 'steelblue')
        .style('fill', 'blue')
        .call(d3.drag()
          .on('start', dragstarted)
          .on('drag', dragged)
          .on('end', dragended));

      node.append('text')
        .text(d => d.name)
        .attr('text-anchor', 'middle')
        .attr('dy', 4)
        .attr('font-size', d => Math.min(2 * d.radius, 20))
        .attr('fill', 'white')
        .style('pointer-events', 'none');

      const linkText = g.selectAll('.linktext')
        .data(data.links)
        .enter()
        .append('text')
        .attr('class', 'linktext')
        .style('fill', 'red')
        .style('font-size', 8)
        .style('text-anchor', 'middle')
        .text(d => d.relate)
        .style('pointer-events', 'none');

      svg.call(d3.zoom().on("zoom", function (event) {
        g.attr("transform", event.transform);
      }));

      simulation
        .on('tick', () => {
          link
            .attr('x1', d => d.source.x)
            .attr('y1', d => d.source.y)
            .attr('x2', d => d.target.x)
            .attr('y2', d => d.target.y);
          node.attr('transform', d => `translate(${d.x},${d.y})`);
          linkText
            .attr('x', d => (d.source.x + d.target.x) / 2)
            .attr('y', d => (d.source.y + d.target.y) / 2);
        });

      function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.5).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(event, d) {
        d.fx = event.x;
        d.fy = event.y;
      }

      function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    }
</script>
<template>
  <div ref="chart" class="graph"></div>
</template>
<style scoped>
.graph {
  background-color: #d1e9ff;
}
</style>